/**
  ETFDAQ Project
  \class TACrate
  \brief A VME Crate holding a controller, and multiple plugin modules
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2024-08-12
  \date 2024-08-12 last modified

  \copyright Copyright (c) 2024 IMP-CAS with LGPLv3 LICENSE
*/

#ifndef event_h
#define event_h

#include <cstdint>
#include <cstring>
#include <iostream>
#include "TAMsg.h"

using std::cout;
using std::endl;
using std::hex;

static const size_t BLKLEN = 8192; // in uint32_t (words)
static const size_t BLKSIZE = 8192*4; // in bytes
static const size_t MAXEVLEN = BLKLEN - 3; // max. ev_len, 3 is len of blk header
static const size_t DMAXEVLEN = 2*BLKLEN - 3; // max. ev_len, 3 is len of blk header

struct event_t{
  uint32_t length; ///< in words
  uint32_t index; ///< event index
  uint32_t nFired; ///< n of fired cards
  uint32_t data[0];

  event_t() : length(3), index(0), nFired(0){}
  void init(){ length = 3; nFired = 0; }
  uint32_t *writePtr() const{ return (uint32_t*)this + length; }
  void print() const{
    cout << "----------- event " << index << " -----------------" << endl;
    cout << "ev_len: " << length << " words(4bytes), ";
    cout << "nof fired cards: " << nFired << endl;
    cout << "this: " << hex << this << ", data: " << hex << data << endl;
    cout << "-- &length: " << hex << &length << ", &index: " << hex << &index << endl;
    cout << " &nFired: " << hex << &nFired << ", &data: " << hex << &data << endl;
    cout << "the write pointer: " << hex << writePtr() << endl;
  } // end member function print
};

struct block_t{
  uint32_t index; ///< block index
  uint32_t ev_num; ///< event number per block
  uint32_t last_pos; ///< the position of the last valid data in the block (in words)
  // we just allocate 2xBLKLEN, instead of BLKLEN, to evade segmentation fault
  // that may be incurred by super-lengthy events
  // well nominally, the whole block is of length BLKLEN, and only the first
  // BLKLEN words of the block will be used (dumped to disk and shm)
  uint32_t ev[2*BLKLEN - 3]; ///< 3 is the len of blk_header

  block_t(){ clear(); }

  void clear(){
    index = ev_num = last_pos = 0;
    memset(ev, 0, sizeof(ev));
  } // end member function clear

  void init(){ // prepare for a new event
    index = 0; ev_num = 0; last_pos = 3;
  } // end member function init

  void reset(){ // prepare for the next block
    index++; ev_num = 0; last_pos = 3;
  } // end member function init

  // insert an event in position of the next event
  // so that ev->data points directly to block memeory
  void initEv(event_t *&e){
    if(last_pos > DMAXEVLEN)
      TAMsg::Error("block_t", "initEv: last_pos out of border: %u", last_pos);
      
    // e = (event_t *)(&index + last_pos);
    e = reinterpret_cast<event_t *>(&index + last_pos);
    e->init();
  } // end member function setev

  void print() const{
    cout << "================== block " << index << " ===============" << endl;
    cout << "nofEv: " << ev_num << ", last_pos: " << last_pos << endl;
  } // end member function print
};

#endif
